package com.dt.common.validation.impl;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;

import com.dt.common.validation.ValidatorConfiguration;
import com.dt.common.validation.ValidatorIdentity;
import com.dt.common.validation.itf.DefinitionReader;
import com.dt.common.validation.itf.PropertyGetter;
import com.dt.common.validation.parser.DefinitionParser;
import com.dt.common.validation.parser.DefinitionParsers;

public class AnnotationDefinitionReader implements DefinitionReader {

	private static List<Field> getAllFieldsList(final Class<?> cls) {
		final List<Field> allFields = new ArrayList<Field>();
		Class<?> currentClass = cls;
		while (currentClass != null) {
			final Field[] declaredFields = currentClass.getDeclaredFields();
			for (final Field field : declaredFields) {
				allFields.add(field);
			}
			currentClass = currentClass.getSuperclass();
		}
		return allFields;
	}

	@Override
	public ObjectValidationDefinition read(ValidatorIdentity id, ValidatorConfiguration configuration) {
		ObjectValidationDefinition objectDefinition = new ObjectValidationDefinition(id);
		List<Field> allFields = getAllFieldsList(configuration.getMetaClass());
		for (Field field : allFields) {
			if (field.isSynthetic()) {
				continue;
			}
			PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(configuration.getMetaClass(),
					field.getName());
			PropertyGetter propertyGetter = new DefaultPropertyGetter(propertyDescriptor,
					configuration.isSupportMapObject());

			for (String type : DefinitionParsers.getPaserTypes()) {
				DefinitionParser parser = DefinitionParsers.getParser(type);
				DefaultValidationDefinition definition = parser.parseFromAnnotation(field, propertyGetter);

				if (definition != null) {
					definition.setPropertyName(field.getName());
					definition.setPropertyGetter(propertyGetter);

					objectDefinition.addPropertyDefinition(definition);
				}
			}
		}

		return objectDefinition;
	}

}
